package com.bing.bingPro.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bing.bingPro.DateUtils;
import com.bing.bingPro.controller.dto.*;
import com.bing.bingPro.controller.vo.DataMissDtoVo;
import com.bing.bingPro.controller.vo.TOrderMissReportFromsVO;
import com.bing.bingPro.controller.vo.TOrderMissReportVo;
import com.bing.bingPro.entity.TOrderMissDetails;
import com.bing.bingPro.entity.TOrderMissMonth;
import com.bing.bingPro.enums.TOderMonthSortEnums;
import com.bing.bingPro.enums.TimeGranularityEnums;
import com.bing.bingPro.mapper.TOrderMissMonthMapper;
import com.bing.bingPro.service.TOrderMissDetailsService;
import com.bing.bingPro.service.TOrderMissMonthService;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.Collator;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author EDY
 * @description 针对表【t_order_miss_month(工单漏传率统计-月)】的数据库操作Service实现
 * @createDate 2023-04-27 21:27:08
 */
@Service
public class TOrderMissMonthServiceImpl extends ServiceImpl<TOrderMissMonthMapper, TOrderMissMonth>
        implements TOrderMissMonthService {

    @Resource
    private TOrderMissMonthMapper tOrderMissMonthMapper;

    @Resource
    private TOrderMissDetailsService tOrderMissDetailsService;


    @Override
    public List<DataMissDtoVo> queryDataTrend(TOrderYearDto tOrderYearDto) {
        List<TOrderMissMonth> tOrderMissMonths = baseMapper.selectList(
                Wrappers.lambdaQuery(TOrderMissMonth.class)
                        .eq(StringUtils.isNotBlank(tOrderYearDto.getProvinceName()), TOrderMissMonth::getProvinceName, tOrderYearDto.getProvinceName())
                        .eq(StringUtils.isNotBlank(tOrderYearDto.getOrderType()), TOrderMissMonth::getOrderType, tOrderYearDto.getOrderType()));
        Map<String, TOrderMissMonth> tOrderMissMonthMap = new HashMap<>();
        tOrderMissMonths.forEach(tOrderMissMonth -> {
            String subMonth = tOrderMissMonth.getMonth().substring(0, 4);
            if (tOrderYearDto.getYear().equals(subMonth)) {
                tOrderMissMonth.setMonth(new StringBuilder(tOrderMissMonth.getMonth()).insert(4, "-").toString());
            }
            tOrderMissMonthMap.put(tOrderMissMonth.getMonth(), tOrderMissMonth);
        });
        return DateUtils.getYearFullMonth(Integer.parseInt(tOrderYearDto.getYear())).stream()
                .map(dataTime -> {
                    DataMissDtoVo vo = new DataMissDtoVo();
                    vo.setDate(dataTime);
                    TOrderMissMonth tOrderMissMonth = tOrderMissMonthMap.get(dataTime);
                    //获取当前月份的第一天
                    YearMonth currentMonth = YearMonth.now();
                    //将传入的dataTime转换为YearMonth对象
                    YearMonth dataTimeMonth = YearMonth.parse(dataTime + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    if (tOrderMissMonth != null) {
                        vo.setOrderMissRate(tOrderMissMonth.getOrderMissRate());
                    } else if (dataTimeMonth.isBefore(currentMonth)) {
                        vo.setOrderMissRate(0D);
                    } else {
                        vo.setOrderMissRate(null);
                    }
                    return vo;
                })
                .collect(Collectors.toList());
    }


    @Override
    public List<TOrderMissReportFromsVO> getTOrderMissReportFromsInfo(TOrderMissReportFromsDTO dto) {
        List<TOrderMissReportFromsVO> tOrderMissReportFromsVOS = new ArrayList<>();
        List<String> fullProvince = new ArrayList<>(Arrays.asList("安徽 北京 福建 甘肃 广东 广西 贵州 海南 河北 河南 黑龙江 湖北 湖南 吉林 江苏 江西 辽宁 内蒙古 宁夏 青海 山东 山西 陕西 上海 四川 天津 西藏 新疆 云南 浙江 重庆 全国".split(" ")));
        if (CharSequenceUtil.isEmpty(dto.getProvinceName())) {
            //时间粒度为日
            if (Objects.equals(TimeGranularityEnums.DAY.getCode(), dto.getTimeGranularity())) {

                List<TOrderMissDetails> tOrderMissDetailsList = tOrderMissDetailsService.getBaseMapper().selectList(Wrappers.lambdaQuery(TOrderMissDetails.class)
                        .le(ObjectUtils.isNotNull(dto.getEndTime()), TOrderMissDetails::getOrderMissTime, dto.getEndTime())
                        .ge(ObjectUtils.isNotNull(dto.getStartTime()), TOrderMissDetails::getOrderMissTime, dto.getStartTime()));
                Map<String, List<TOrderMissDetails>> provinceMap = tOrderMissDetailsList.stream().collect(Collectors.groupingBy(TOrderMissDetails::getProvinceName));

                provinceMap.forEach((provinceName, provinceDetailsList) -> {
                    fullProvince.remove(provinceName);
                    TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
                    vo.setFirstLetter(getFirstLetter(provinceName));
                    //组装数据返回
                    extracted(tOrderMissReportFromsVOS, provinceName, provinceDetailsList, vo);
                });
                if (CollUtil.isNotEmpty(fullProvince)) {
                    fullProvince.forEach(provinceName -> {
                        TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
                        vo.setProvinceName(provinceName);
                        vo.setFirstLetter(getFirstLetter(provinceName));
                        vo.setDayCount(null);
                        vo.setTOrderMissDetailsDTOList(null);
                        tOrderMissReportFromsVOS.add(vo);
                    });
                }
                Comparator<TOrderMissReportFromsVO> comparator = Comparator.comparing(TOrderMissReportFromsVO::getFirstLetter, Collator.getInstance(Locale.CHINA));
                tOrderMissReportFromsVOS.sort(comparator);

                return tOrderMissReportFromsVOS;
            }
            //时间粒度为月
            String formatTime = dto.getTime();
            String replace = formatTime.replace("-", "");

            List<TOrderMissMonth> orderMissMonthIPage = tOrderMissMonthMapper.selectList(Wrappers.lambdaQuery(TOrderMissMonth.class)
                    .eq(TOrderMissMonth::getMonth, replace));
            //key 城市名称
            Map<String, List<TOrderMissMonth>> tOrderMissMonthMap = orderMissMonthIPage.stream().collect(Collectors.groupingBy(TOrderMissMonth::getProvinceName));

            tOrderMissMonthMap.forEach((provinceName, tOrderMissMonthList) -> {
                fullProvince.remove(provinceName);
                TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
                //工单类型集合
                List<TOrderMissDetailsDTO> tOrderMissDetailsDTOS = new ArrayList<>();

                vo.setProvinceName(provinceName);
                vo.setFirstLetter(getFirstLetter(provinceName));
                //不同类型的工单漏传率
                tOrderMissMonthMap.get(provinceName).forEach(tOrderMissMonth -> {
                    List<String> dateList = new ArrayList<>();
                    TOrderMissDetailsDTO tOrderMissDetailsDTO = new TOrderMissDetailsDTO();
                    tOrderMissDetailsDTO.setOrderType(tOrderMissMonth.getOrderType());
                    tOrderMissDetailsDTO.setOrderMissRate(tOrderMissMonth.getOrderMissRate());
                    List<TOrderMissDetails> tOrderMissDetailsList = gettOrderMissDetails(formatTime, provinceName, tOrderMissMonth, dateList);

                    //时间排序
                    List<String> collects = dateList.stream().sorted().collect(Collectors.toList());
                    //漏传天数
                    tOrderMissDetailsDTO.setCount(tOrderMissDetailsList.size());
                    //漏传日期
                    tOrderMissDetailsDTO.setOrderMissDateList(collects);
                    tOrderMissDetailsDTOS.add(tOrderMissDetailsDTO);

                });
                vo.setTOrderMissDetailsDTOList(tOrderMissDetailsDTOS);
                tOrderMissReportFromsVOS.stream()
                        .filter(chinaVO -> "全国".equals(chinaVO.getProvinceName()))
                        .flatMap(chinaVO -> chinaVO.getTOrderMissDetailsDTOList().stream())
                        .forEach(orderTypeDto -> {
                            orderTypeDto.setOrderMissDateList(getAllOrderMissDateList(tOrderMissReportFromsVOS, orderTypeDto));
                            orderTypeDto.setCount(orderTypeDto.getOrderMissDateList().size());
                        });
                tOrderMissReportFromsVOS.add(vo);
            });

            if (CollUtil.isNotEmpty(fullProvince)) {
                fullProvince.forEach(province -> {
                    TOrderMissReportFromsVO tOrderMissDetailsDTO = new TOrderMissReportFromsVO();
                    tOrderMissDetailsDTO.setProvinceName(province);
                    tOrderMissDetailsDTO.setFirstLetter(getFirstLetter(province));
                    tOrderMissDetailsDTO.setTOrderMissDetailsDTOList(null);
                    tOrderMissDetailsDTO.setDayCount(null);
                    tOrderMissReportFromsVOS.add(tOrderMissDetailsDTO);
                });
            }
            Comparator<TOrderMissReportFromsVO> comparator = Comparator.comparing(TOrderMissReportFromsVO::getFirstLetter, Collator.getInstance(Locale.CHINA));
            tOrderMissReportFromsVOS.sort(comparator);
            // 将全国省份数据移到最后
            Optional<TOrderMissReportFromsVO> chinaOptional = tOrderMissReportFromsVOS.stream().filter(vo -> "全国".equals(vo.getProvinceName())).findFirst();
            chinaOptional.ifPresent(chinaVO -> {
                tOrderMissReportFromsVOS.remove(chinaVO);
                tOrderMissReportFromsVOS.add(chinaVO);
            });
            return tOrderMissReportFromsVOS;
        }

        String provinceName = dto.getProvinceName();
        //获取单条时间粒度为日的
        if (Objects.equals(TimeGranularityEnums.DAY.getCode(), dto.getTimeGranularity())) {
            List<TOrderMissDetails> tOrderMissDetailsList = tOrderMissDetailsService.getBaseMapper().selectList(Wrappers.lambdaQuery(TOrderMissDetails.class)
                    .le(ObjectUtils.isNotNull(dto.getEndTime()), TOrderMissDetails::getOrderMissTime, dto.getEndTime())
                    .ge(ObjectUtils.isNotNull(dto.getStartTime()), TOrderMissDetails::getOrderMissTime, dto.getStartTime())
                    .eq(TOrderMissDetails::getProvinceName, provinceName));
            //校验数据库里有没有该省份
            if (CollUtil.isEmpty(tOrderMissDetailsList)) {
                TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
                vo.setProvinceName(provinceName);
                vo.setDayCount(null);
                tOrderMissReportFromsVOS.add(vo);
                return tOrderMissReportFromsVOS;
            }
            //有该省份
            Map<String, List<TOrderMissDetails>> provinceMap = tOrderMissDetailsList.stream().collect(Collectors.groupingBy(TOrderMissDetails::getOrderType));

            provinceMap.forEach((proName, provinceDetailsList) -> {
                TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
                extracted(tOrderMissReportFromsVOS, provinceName, provinceDetailsList, vo);
            });
            return tOrderMissReportFromsVOS;
        }
        //获取单个城市时间粒度为月
        String formatTime = dto.getTime();
        String replace = formatTime.replace("-", "");
        //工单类型集合
        List<TOrderMissDetailsDTO> tOrderMissDetailsDTOSSingleton = new ArrayList<>();
        List<TOrderMissMonth> tOrderMissMonthList = tOrderMissMonthMapper.selectList(Wrappers.lambdaQuery(TOrderMissMonth.class)
                .eq(TOrderMissMonth::getMonth, replace)
                .eq(TOrderMissMonth::getProvinceName, provinceName));
        TOrderMissReportFromsVO vo = new TOrderMissReportFromsVO();
        tOrderMissMonthList.forEach(tOrderMissMonth -> {
            List<String> dateList = new ArrayList<>();
            TOrderMissDetailsDTO tOrderMissDetailsDTO = new TOrderMissDetailsDTO();
            tOrderMissDetailsDTO.setOrderType(tOrderMissMonth.getOrderType());
            tOrderMissDetailsDTO.setOrderMissRate(tOrderMissMonth.getOrderMissRate());
            List<TOrderMissDetails> tOrderMissDetailsList = gettOrderMissDetails(formatTime, provinceName, tOrderMissMonth, dateList);
            //漏传天数
            tOrderMissDetailsDTO.setCount(tOrderMissDetailsList.size());
            //漏传日期
            tOrderMissDetailsDTO.setOrderMissDateList(dateList);
            tOrderMissDetailsDTOSSingleton.add(tOrderMissDetailsDTO);
            vo.setProvinceName(provinceName);
            vo.setTOrderMissDetailsDTOList(tOrderMissDetailsDTOSSingleton);
        });
        tOrderMissReportFromsVOS.add(vo);
        return tOrderMissReportFromsVOS;
    }

    private List<TOrderMissDetails> gettOrderMissDetails(String formatTime, String provinceName, TOrderMissMonth tOrderMissMonth, List<String> dateList) {
        //漏传日期
        List<TOrderMissDetails> tOrderMissDetailsList = tOrderMissDetailsService.getBaseMapper().selectList(Wrappers.lambdaQuery(TOrderMissDetails.class)
                .eq(TOrderMissDetails::getProvinceName, provinceName)
                .like(TOrderMissDetails::getOrderMissTime, formatTime)
                .eq(TOrderMissDetails::getOrderType, tOrderMissMonth.getOrderType()));
        List<LocalDate> missDates = tOrderMissDetailsList.stream().map(TOrderMissDetails::getOrderMissTime).collect(Collectors.toList());
        missDates.forEach(date -> {
            String format = LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);
            String sub = CharSequenceUtil.sub(format, 5, 10);
            dateList.add(sub);
        });
        return tOrderMissDetailsList;
    }

    private void extracted(List<TOrderMissReportFromsVO> tOrderMissReportFromsVOS, String provinceName, List<TOrderMissDetails> provinceDetailsList, TOrderMissReportFromsVO vo) {
        //工单类型集合
        List<TOrderDetailsDTO> orderDetailsList = new ArrayList<>();
        vo.setProvinceName(provinceName);
        //key  工单类型
        Map<String, List<TOrderMissDetails>> orderTypeMap = provinceDetailsList.stream().collect(Collectors.groupingBy(TOrderMissDetails::getOrderType));
        orderTypeMap.forEach((orderType, orderTypeDetailsList) -> {
            TOrderDetailsDTO detailsDTO = new TOrderDetailsDTO();
            detailsDTO.setOrderType(orderType);
            detailsDTO.setCount(orderTypeDetailsList.size());
            orderDetailsList.add(detailsDTO);
        });
        vo.setDayCount(orderDetailsList);
        tOrderMissReportFromsVOS.add(vo);
    }


    public List<String> getAllOrderMissDateList(List<TOrderMissReportFromsVO> tOrderMissReportFromsVOS, TOrderMissDetailsDTO tOrderMissDetailsDTO) {
        String orderType = tOrderMissDetailsDTO.getOrderType();
        Set<String> allOrderMissDateSet = tOrderMissReportFromsVOS.stream()
                .flatMap(vo -> vo.getTOrderMissDetailsDTOList().stream())
                .filter(dto -> dto.getOrderType().equals(orderType))
                .flatMap(dto -> dto.getOrderMissDateList().stream())
                .collect(Collectors.toSet());
        // 转成List并按照MM-dd格式排序
        return allOrderMissDateSet.stream().sorted().collect(Collectors.toList());
    }

    public static String getFirstLetter(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        String convert = "";
        char word = str.charAt(0);
        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
        if (pinyinArray != null) {
            convert += pinyinArray[0].charAt(0);
        } else {
            convert += word;
        }
        return convert.toUpperCase();
    }


    @Override
    public List<TOrderMissReportVo> queryDataSort(TOrderMissReportDTO reportDTO) {
        List<TOrderMissReportVo> tOrderMissReportVoList = new ArrayList<>();
        List<String> fullProvince = getProvince();
        if (Objects.equals(TimeGranularityEnums.YEAR.getCode(), reportDTO.getTimeGranularity())) {
            String replace = reportDTO.getTime().replace("-", "");
            LambdaQueryWrapper<TOrderMissMonth> lambdaQueryWrapper = Wrappers.lambdaQuery(TOrderMissMonth.class)
                    .eq(TOrderMissMonth::getMonth, replace)
                    .eq(CharSequenceUtil.isNotBlank(reportDTO.getOrderType()), TOrderMissMonth::getOrderType, reportDTO.getOrderType());
            List<TOrderMissMonth> tOrderMissMonths = tOrderMissMonthMapper.selectList(lambdaQueryWrapper);
            List<String> selectedProvince = tOrderMissMonths.stream().map(TOrderMissMonth::getProvinceName).filter(fullProvince::contains).distinct().collect(Collectors.toList());
            selectedProvince.forEach(provinceName -> {
                TOrderMissReportVo vo = new TOrderMissReportVo();
                vo.setProvinceName(provinceName);
                List<TOrderMissMonth> tOrderMissMonthEntities = tOrderMissMonths.stream().filter(tOrderMissMonth -> tOrderMissMonth.getProvinceName().equals(provinceName)).collect(Collectors.toList());
                vo.setOrderMissRate(CollUtil.isNotEmpty(tOrderMissMonthEntities) ? tOrderMissMonthEntities.get(0).getOrderMissRate() : 0D);
                tOrderMissReportVoList.add(vo);
            });
            fullProvince.removeAll(selectedProvince);

            LocalDate currentDate = LocalDate.now();
            LocalDate targetDate = LocalDate.parse(reportDTO.getTime() + "-01");
            for (String province : fullProvince) {
                TOrderMissReportVo vo = new TOrderMissReportVo();
                vo.setProvinceName(province);
                vo.setOrderMissRate(targetDate.isBefore(currentDate.withDayOfMonth(1)) ? 0D : null);
                tOrderMissReportVoList.add(vo);
            }
            return getOrderMissReportVos(reportDTO, tOrderMissReportVoList);
        }
        List<TOrderMissDetails> tOrderMissDetailsList = tOrderMissDetailsService.getBaseMapper().selectList(Wrappers.lambdaQuery(TOrderMissDetails.class)
                .le(reportDTO.getEndTime() != null, TOrderMissDetails::getOrderMissTime, reportDTO.getEndTime())
                .ge(reportDTO.getStartTime() != null, TOrderMissDetails::getOrderMissTime, reportDTO.getStartTime())
                .eq(CharSequenceUtil.isNotBlank(reportDTO.getOrderType()), TOrderMissDetails::getOrderType, reportDTO.getOrderType()));

        Map<String, List<TOrderMissDetails>> map = tOrderMissDetailsList.parallelStream().collect(Collectors.groupingBy(TOrderMissDetails::getProvinceName));

        map.forEach((provinceName, tOrderMissDetails) -> {
            fullProvince.remove(provinceName);
            long day = ChronoUnit.DAYS.between(reportDTO.getStartTime(), reportDTO.getEndTime()) + 1;
            int size = tOrderMissDetails.size();
            BigDecimal decimal = BigDecimal.valueOf((double) size / day);
            BigDecimal rate = decimal.setScale(4, RoundingMode.HALF_UP);
            TOrderMissReportVo reportVo = new TOrderMissReportVo();
            reportVo.setProvinceName(provinceName);
            reportVo.setOrderMissRate(rate.doubleValue());
            tOrderMissReportVoList.add(reportVo);
        });
        if (CollUtil.isNotEmpty(fullProvince)) {
            LocalDate today = LocalDate.now();
            LocalDate startTime = reportDTO.getStartTime();
            fullProvince.forEach(province -> {
                TOrderMissReportVo vo = new TOrderMissReportVo();
                vo.setProvinceName(province);
                //开始时间早于今天-0   等于或晚于今天-null
                vo.setOrderMissRate(startTime.isBefore(today)  ?  0D  :  null);
                tOrderMissReportVoList.add(vo);
            });
        }

        return getOrderMissReportVos(reportDTO, tOrderMissReportVoList);
    }

    private List<String> getFullProvince() {
        return getStrings();
    }

    private List<String> getStrings() {
        return new ArrayList<>(Arrays.asList("安徽 北京 福建 甘肃 广东 广西 贵州 海南 河北 河南 黑龙江 湖北 湖南 吉林 江苏 江西 辽宁 内蒙古 宁夏 青海 山东 山西 陕西 上海 四川 天津 西藏 新疆 云南 浙江 重庆 全国".split(" ")));
    }

    private List<String> getProvince() {
        return getCountryStrings();
    }

    private List<String> getCountryStrings() {
        return new ArrayList<>(Arrays.asList("安徽 北京 福建 甘肃 广东 广西 贵州 海南 河北 河南 黑龙江 湖北 湖南 吉林 江苏 江西 辽宁 内蒙古 宁夏 青海 山东 山西 陕西 上海 四川 天津 西藏 新疆 云南 浙江 重庆".split(" ")));
    }

    private List<TOrderMissReportVo> getOrderMissReportVos(TOrderMissReportDTO reportDTO, List<TOrderMissReportVo> tOrderMissReportVoList) {
        //升序
        if (Objects.equals(TOderMonthSortEnums.ASC.getCode(), reportDTO.getSort())) {
            return Objects.requireNonNull(tOrderMissReportVoList).stream()
                    .sorted(Comparator.comparing(
                            tOrderMissReportVo -> Optional.ofNullable(tOrderMissReportVo.getOrderMissRate()).orElse(Double.MAX_VALUE)))
                    .collect(Collectors.toList());
        }
        //降序
        else {
            return Objects.requireNonNull(tOrderMissReportVoList).stream()
                    .sorted(Comparator.comparing(
                            tOrderMissReportVo -> Optional.ofNullable(tOrderMissReportVo.getOrderMissRate()).orElse(Double.MAX_VALUE),
                            Comparator.reverseOrder()))
                    .collect(Collectors.toList());
        }
    }


}




